﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum HairUnitEndType
{
    Sharp,
    Flat
}
public class HairUnit : MonoBehaviour
{
    public HairUnitBaker baker;
    public HairUnitGroupShape shape;
    public SkinnedMeshRenderer smr;
    public int endType;
    public Color rangeHlColor;
    public float rangeHlPower;
    public Color rimColor;
    public float rimPower;
    public bool rimOn;
    public Color matCapColor;
    public Color lightColor;
    public float darkStep;
    public float darkFeather;
    public Color darkColor;
    public float dark2Step;
    public float dark2Feather;
    public Color dark2Color;
    public Vector2 matCapOffset;
    public Vector2 matCapScale;
    public float[] sectionWidth;
    public float[] sectionThickness;
    public Vector3[] sectionPosition;
    public Quaternion[] sectionRotation;

    public string data;
    public bool busy;
    public List<string> sign;
    public const string signCapacity = "P00:";
    // All the values plus 1 str to mark it's sign
    public const float hex2factor = 1f / 255f;
    float Hex2ToFloat
    {
        get
        {
            string hex = Read(2); // no sign
            int d = Int32.Parse(hex, System.Globalization.NumberStyles.HexNumber);
            float v = d * hex2factor;
            return v;
        }
    }
    public string colorMark = "C";
    Color Hex6ToColor
    {
        get
        {
            if (Read(colorMark.Length) != colorMark) throw new Exception("Color Mark miss");
            Color c = new Color(Hex2ToFloat, Hex2ToFloat, Hex2ToFloat);
            return c;
        }
    }
    string ColorToHex6(Color c)
    {
        var format = "X2";
        var range = 255;
        int r = (int)(c.r * range);
        int g = (int)(c.g * range);
        int b = (int)(c.b * range);
        return colorMark + r.ToString(format) + g.ToString(format) + b.ToString(format);
    }
    public float String5ToFloat1_3
    {
        get
        {
            string s = Read(5);
            int i;
            int.TryParse(s, out i);
            float v = i * 0.001f;
            return v;
        }
    }
    public string Float1_3ToString5(float v)
    {
        v *= 1000;
        int i = (int)v;
        var format = "0000"; // 整数1位 + 小数3位 + 符号1位
        var s = i.ToString(format);
        if (i >= 0) s = "+" + s;
        if (s.Length != 5) { Debug.LogError(s); throw new Exception("len diff"); }
        return s;
    }
    public float String7ToFloat1_5
    {
        get
        {
            string s = Read(7);
            int i;
            int.TryParse(s, out i);
            float v = i * 0.00001f;
            return v;
        }
    }
    public string Float1_5ToString7(float v)
    {
        v *= 100000;
        int i = (int)v;
        var format = "000000"; // 整数1位 + 小数5位 + 符号1位
        var s = i.ToString(format);
        if (i >= 0) s = "+" + s;
        if (s.Length != 7) { Debug.LogError(s); throw new Exception("len diff"); }
        return s;
    }
    public float String6ToFloat
    {
        get
        {
            string s = Read(6);
            int i;
            int.TryParse(s, out i);
            float v = i * 0.01f;
            return v;
        }
    }
    public string FloatToString6(float v)
    {
        v *= 100;
        int i = (int)v;
        var format = "00000"; // 整数3位 + 小数2位 + 符号1位
        var s = i.ToString(format);
        if (i >= 0) s = "+" + s;
        if (s.Length != format.Length + 1) { Debug.LogError(s); throw new Exception("len diff"); }
        return s;
    }
    public Quaternion String28ToVector4
    {
        get
        {
            Quaternion v;
            v.x = String7ToFloat1_5;
            v.y = String7ToFloat1_5;
            v.z = String7ToFloat1_5;
            v.w = String7ToFloat1_5;
            return v;
        }
    }
    public string Vector4ToString28(Quaternion v)
    {
        string s = Float1_5ToString7(v.x) + Float1_5ToString7(v.y) + Float1_5ToString7(v.z) + Float1_5ToString7(v.w);
        return s;
    }
    public Vector3 String21ToVector3
    {
        get
        {
            Vector3 v;
            v.x = String7ToFloat1_5;
            v.y = String7ToFloat1_5;
            v.z = String7ToFloat1_5;
            return v;
        }
    }
    public string Vector3ToString21(Vector3 v)
    {
        string s = Float1_5ToString7(v.x) + Float1_5ToString7(v.y) + Float1_5ToString7(v.z);
        return s;
    }
    private int String4ToInt
    {
        get
        {
            string s = Read(4);
            int i;
            int.TryParse(s, out i);
            return i;
        }
    }
    private string IntToString4(int i)
    {
        var s = i.ToString("000");// 3num + 1sign
        if (i >= 0) s = "+" + s;
        return s;
    }
    public bool String1ToBool
    {
        get
        {
            string s = Read(1); // no sign
            int i;
            int.TryParse(s, out i);
            bool v = i != 0;
            return v;
        }
    }
    public string BoolToString1(bool v)
    {
        int i = v ? 1 : 0;
        return i.ToString();
    }
    string Read(int count)
    {
        var sec = data.Substring(0, count);
        data = data.Substring(count);
        return sec;
    }
    void ReadSign()
    {
        sign.Add(Read(signCapacity.Length));
    }
    public string Sign
    {
        get
        {
            var s = "P" + signIndex.ToString("00") + ":";
            signIndex++;
            return s;
        }
    }
    public int signIndex;
    public void ReadValuesFromFaceCode(string v)
    {
        if (v.Length == 0) return;
        data = v;

        sign.Clear();
        ReadSign();
        endType = String4ToInt;
        rangeHlColor = Hex6ToColor;
        rangeHlPower = String6ToFloat;
        rimColor = Hex6ToColor;
        rimPower = String6ToFloat;
        rimOn = String1ToBool;

        ReadSign();
        matCapColor = Hex6ToColor;
        lightColor = Hex6ToColor;
        darkStep = String6ToFloat;
        darkFeather = String6ToFloat;
        darkColor = Hex6ToColor;
        dark2Step = String6ToFloat;
        dark2Feather = String6ToFloat;
        dark2Color = Hex6ToColor;

        ReadSign();
        matCapOffset.x = String6ToFloat;
        matCapOffset.y = String6ToFloat;
        matCapScale.x = String6ToFloat;
        matCapScale.y = String6ToFloat;
        ReadSign();
        for (int i = 0; i < sectionWidth.Length; i++)
        {
            sectionWidth[i] = String6ToFloat;
        }
        ReadSign();
        for (int i = 0; i < sectionThickness.Length; i++)
        {
            sectionThickness[i] = String6ToFloat;
        }
        ReadSign();
        for (int i = 0; i < sectionPosition.Length; i++)
        {
            sectionPosition[i] = String21ToVector3;
        }
        ReadSign();
        for (int i = 0; i < sectionRotation.Length; i++)
        {
            sectionRotation[i] = String28ToVector4;
        }
    }
    public string GenerateReadableFaceCode()
    {
        string str = "";
        signIndex = 0;
        str += Sign;
        str += IntToString4(endType);
        str += ColorToHex6(rangeHlColor);
        str += FloatToString6(rangeHlPower);
        str += ColorToHex6(rimColor);
        str += FloatToString6(rimPower);
        str += BoolToString1(rimOn);

        str += Sign;
        str += ColorToHex6(matCapColor);
        str += ColorToHex6(lightColor);
        str += FloatToString6(darkStep);
        str += FloatToString6(darkFeather);
        str += ColorToHex6(darkColor);
        str += FloatToString6(dark2Step);
        str += FloatToString6(dark2Feather);
        str += ColorToHex6(dark2Color);

        str += Sign;
        str += FloatToString6(matCapOffset.x);
        str += FloatToString6(matCapOffset.y);
        str += FloatToString6(matCapScale.x);
        str += FloatToString6(matCapScale.y);
        str += Sign;
        for (int i = 0; i < sectionWidth.Length; i++)
        {
            str += FloatToString6(sectionWidth[i]);
        }
        str += Sign;
        for (int i = 0; i < sectionThickness.Length; i++)
        {
            str += FloatToString6(sectionThickness[i]);
        }
        str += Sign;
        for (int i = 0; i < sectionPosition.Length; i++)
        {
            str += Vector3ToString21(sectionPosition[i]);
        }
        str += Sign;
        for (int i = 0; i < sectionRotation.Length; i++)
        {
            str += Vector4ToString28(sectionRotation[i]);
        }
        return str;
    }
    public HairUnit mirror;
    public void Init()
    {
        baker = GetComponentInChildren<HairUnitBaker>();
        baker.Init();
        shape = GetComponentInChildren<HairUnitGroupShape>();
        smr = GetComponentInChildren<SkinnedMeshRenderer>();
        var n = Instantiate(smr.sharedMaterial);
        smr.sharedMaterials = new Material[] { n, n };
        collider = smr.GetComponent<MeshCollider>();
        sectionWidth = new float[8] { 1, 1, 1, 1, 1, 1, 1, 1 };
        sectionThickness = new float[8] { 1, 1, 1, 1, 1, 1, 1, 1 };
        sectionPosition = new Vector3[9];
        sectionRotation = new Quaternion[9];
        sign = new List<string>();

    }
    public void SetSectionTrans(Vector3[] secPoss, Quaternion[] secRots)
    {
        for (int i = 0; i < secPoss.Length; i++)
        {
            baker.bones[i].position = sectionPosition[i] = secPoss[i];
            baker.bones[i].rotation = sectionRotation[i] = secRots[i];
        }
        UpdateColliderAndSectionTrans();
    }
    public void UpdateSectionTrans()
    {
        for (int i = 0; i < baker.bones.Length; i++)
        {
            sectionPosition[i] = baker.bones[i].position;
            sectionRotation[i] = baker.bones[i].rotation;
        }
    }
    [SerializeField]
    new MeshCollider collider;
    public void UpdateCollider()
    {
        Mesh colliderMesh = new Mesh();
        smr.BakeMesh(colliderMesh);

        var verts = colliderMesh.vertices;
        for (int i = 0; i < verts.Length; i++)
        {
            verts[i] = Vector3.Scale(Vector3.one * 25f, verts[i]);// smr scale = 0.04f
        }
        colliderMesh.vertices = verts;
        collider.sharedMesh = null;
        collider.sharedMesh = colliderMesh;
    }
    public void UpdateColliderAndSectionTrans()
    {
        UpdateSectionTrans();
        UpdateCollider();
    }
}
